//  Copyright (c) Microsoft Corporation.  All Rights Reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IdentityModel.Selectors;
using System.Globalization;

namespace EAI.SAML
{
    public class EAISamlConditions
    {
        DateTime notBefore = DateTime.MinValue.ToUniversalTime();
        DateTime notOnOrAfter = DateTime.MaxValue.ToUniversalTime();
        readonly ImmutableCollection<EAISamlCondition> conditions = new ImmutableCollection<EAISamlCondition>();

        bool isReadOnly = false;

        public EAISamlConditions()
        {
        }

        public EAISamlConditions(XmlReader reader, EAISamlSerializer serializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
        {
            this.ReadXml(reader, serializer, keyInfoSerializer, outOfBandTokenResolver);
        }

        public DateTime NotBefore
        {
            get { return this.notBefore; }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("Object is Read-Only");
                this.notBefore = value;
            }
        }

        public DateTime NotOnOrAfter
        {
            get { return this.notOnOrAfter; }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("Object is Read-Only");
                this.notOnOrAfter = value;
            }
        }

        public IList<EAISamlCondition> Conditions
        {
            get
            {
                return this.conditions;
            }
        }

        public void MakeReadOnly()
        {
            if (!this.isReadOnly)
            {
                this.conditions.MakeReadOnly();
                this.isReadOnly = true;
            }
        }

        public virtual void ReadXml(XmlReader reader, EAISamlSerializer serializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            string attributeValue = reader.GetAttribute(EAISamlConstants.NotBeforeAttribute);
            if (!String.IsNullOrEmpty(attributeValue))
                this.notBefore = Convert.ToDateTime(attributeValue).ToUniversalTime();

            attributeValue = reader.GetAttribute(EAISamlConstants.NotOnOrAfterAttribute, EAISamlConstants.Namespace);
            if (!String.IsNullOrEmpty(attributeValue))
                this.notOnOrAfter = Convert.ToDateTime(attributeValue).ToUniversalTime();

            if (reader.IsEmptyElement)
            {
                reader.MoveToContent();
                reader.Read();
                return;
            }

            reader.MoveToContent();
            reader.Read();
            while (reader.IsStartElement())
            {
                string localName = reader.LocalName;
                EAISamlCondition condition = serializer.LoadCondition(reader, keyInfoSerializer, outOfBandTokenResolver);
                if (condition == null)
                    throw new SecurityTokenException(String.Format("Unable to load '<{0}>' element inside the <saml:Conditions> element.", localName));

                this.conditions.Add(condition);
            }

            reader.ReadEndElement();
        }

        public virtual void WriteXml(XmlWriter writer, SecurityTokenSerializer tokenSerializer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            writer.WriteStartElement(EAISamlConstants.Conditions, EAISamlConstants.Namespace);
            if (this.notBefore != DateTime.MinValue.ToUniversalTime())
                writer.WriteAttributeString(EAISamlConstants.NotBeforeAttribute, this.notBefore.ToString(EAISamlConstants.GeneratedDateTimeFormat, DateTimeFormatInfo.InvariantInfo));

            if (this.notOnOrAfter != DateTime.MaxValue.ToUniversalTime())
                writer.WriteAttributeString(EAISamlConstants.NotOnOrAfterAttribute, this.notOnOrAfter.ToString(EAISamlConstants.GeneratedDateTimeFormat, DateTimeFormatInfo.InvariantInfo));

            for (int i = 0; i < this.conditions.Count; ++i)
                this.conditions[i].WriteXml(writer, tokenSerializer);

            writer.WriteEndElement();
        }
    }
}
